//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "bulverde_macros.inc"
#include "bulverde_base_regs.inc"
//#include "mainstoneii.inc"
#include "xlli_Bulverde_defs.inc"
#include "xlli_Mainstone_defs.inc"

/* memory address */
#define RAM_START				0xA0000000
#define RAM_BOOT_LOADER_AREA_START_OFFSET_FROM_RAM_START 0x03C00000
#define RAM_BOOT_LOADER_AREA_LENGTH  0x00100000
#define RAM_STACK_END_OFFSET_FROM_RAM_START 0x03FFFFFC
#define KERNEL_RAM_START		0xA0020000//0xA0208000

#define SPL_RAM_ADDRESS         0xA3C00000
#define MDOCPBaseAddress        0x00000000
#define SPL_SIZE                0x400
#define SPL_SIGN                0x544F4F42
#define CDSN_IO     0x0800
#define CDSN_IO_CORR     0x02
#define CDSN_CNTR     0x1000
#define MDOCPBaseAddressIO      (MDOCPBaseAddress + CDSN_IO)
#define MDOCPBaseAddressCNTR    (MDOCPBaseAddress + CDSN_CNTR)
#define G3_NNOPreg     0x3E
#define G3_NDOCcontrol     0x0C
#define G3_NDOCcontrolConfirm     0x72
#define G3_NdeviceSelect     0x0A
#define G3_NflashSequence     0x32
#define G3_NflashCommand     0x34
#define G3_NflashDataEnd     0x1E
#define G3_NflashAddress     0x36
#define G3_NflashControl     0x38
#define G3_NECCcontrol_0     0x40
#define G3_NECCcontrol_1     0x42
#define G3_NreadAddrReg     0x1A
#define G3_EDC_ERROR_MASK     0x80
#define G3_EDC_VAL     0x8A0F
#define RESET_FLASH_CMD     0xFF
#define READ_A_FLASH_CMD     0x0
#define READ_C_FLASH_CMD     0x50
#define SLC_MODE_CMD         0xA2
#define RELIABLE_SLC_MODE_CMD  0x22
#define FAST_MODE_CMD     0xA2
#define RELIABLE_MODE_CMD     0x22
#define AUTO_PAGE_INC_CMD     0xB3
#define READ_CMD     0x60
#define MULTI_READ_CMD     0x30
#define REGISTER_READ_CMD     0xE0
#define ADDR_INPUT_FOR_REG_READ     0x05
#define G3_PLANE_0     0x00
#define G3_PLANE_1     0x40
#define ResetFlash_Seq     0
#define READ_A_Seq     14
#define READ_C_Seq     16
#define SLC_MODE_Seq           9
#define FAST_MODE_Seq     9
#define AUTO_PAGE_INC_Seq     12
#define READ_Seq     18
#define IPL_MAX_ID     0x30
#define G3_RB_SHIFT     31
#define G3_CDSN_CE     0x39
#define G3_ACCESS_ERR     0x06
#define DOC_CTRL_NORMAL_MODE     0x05

#define BLOCK_DATA     0x200
#define DUMMY_DATA     10
#define G3_EDC_DATA     16
#define G3_PAGE_OFFSET          0x84
#define G3_SIGN_OFFSET          0x80
#define END_SPL_ADDR     0x1000/2
#define G3_SPL_NEXT             0x80
#define SPL_START               0x80
#define MDOC32_ID     0x40
#define MDOC512_ID     0x20
#define G3_PAGES_IN_UNIT     0x40

#define BAUD_4800    0xC0 @  UART Divisor low bye setting for 4800 baud
#define BAUD_9600    0x60 @  UART Divisor low bye setting for 9600 baud
#define BAUD_19200   0X30 @  UART Divisor low bye setting for 19200 baud
#define BAUD_38400   0x18 @  UART Divisor low bye setting for 38400 baud
#define BAUD_57600   0x10 @  UART Divisor low bye setting for 57600 baud
#define BAUD_115200  0X08 @  UART Divisor low bye setting for 115200 baud


#define TDRQ     0x20   @  Transmit Data Request
#define TEMT     0x40	@  Transmitter Empty bit
#define DR       0x01	@  Data Ready bit
#define DLAB     0x80   @  DLAB bit
#define nBT_OFF  0x100  @  BTUART Tranceiver Control Bit
#define BTDTR    0x80 	@  BTUART Data Terminal Ready bit


.text
	/* Jump vector table as in table 3.1 in [1] */
.globl _mainCRTStartup
_mainCRTStartup:
    b	reset
	b	undefined_instruction
	b	software_interrupt
	b	abort_prefetch
	b	abort_data
	b	not_used
	b	irq
	b	fiq

reset:
	 mov	r0, #0x13	// set into Supervisior mode
	 orr	r0, r0, #0xC0	// disable IRQ, FIQ
	 msr	cpsr, r0

     bl     PREINIT
	 bl	    Init_GPIO

	 //bl	    Init_INT


	 bl     Init_Uart

	 mov	r2, #0x61
	 bl	    UartPrintch

	 bl     Init_Mem

	 bl	    MDOC_Copy

RAMBEGIN:

	mov	r2, #0x62
	bl	UartPrintch

	/* Set up the user and irq stack pointer */
	ldr r1, =M_START
	ldr r2, =M_STACK_END_OFFSET_FROM_RAM_START
	add r1, r1, r2
	sub sp, r1, #0x1000 /* set IRQ sp : 0x100 bytes lower from the IRQ sp */
			/* If you need more stack space in interrupt, you can increase this value (0x100) to much as you want */

	/* Jump to the C code */
	/* from here, copy the main code from flash to RAM.
	 * interrupt vector contents should be changed,
	 * as they use bl or other method for communication
	 * this code should be modified to jump to #0xc?????
	 * as we need to jump from flash to RAM
	 */
	/* check copy from 16 bits to 32 bits */

	/* copy data from the flash to ram */
	/*
	 *       Flash 16MBx16bits (32MB)       SDRAM 16MBx16bits (32MB)
	 *       +----------+               r9->+----------+
	 *       |          |                   |   Stack  |
	 *       |          |               r8->|..........|
	 *       |          |                   |          |
	 *       |          |                   |BootLoader|
	 *       |          |                   |          |
	 *       |          |         r6,r7(1)->|..........|
	 *       |          |                   |          |
	 *       |          |                   |          |
	 *       |          |                   |          |
	 *       |          |                   |          |
	 *       |          |                   |          |
	 *       |          |                   |          |
	 *       |          |                   |          |
	 *       |          |                   |          |
	 *       |          |                   |          |
	 *       |----------| --                |          |
	 *       |          | /\                |          |
	 *       |BootLoader| ||                |          |
	 *       |          | \/                |          |
	 *       +----------+ --         r7(0)->+----------+
	 *
	 */
	/* clear the BSS section */
	ldr	r1, bss_start
	ldr	r0, bss_end
	sub	r0, r0, r1

	/* r1 = start address */
	/* r0 = *number of bytes */
	mov	r2, #0
	mov r3, #0
	mov	r4, #0
	mov	r5, #0

clear_bss:
	stmia	r1!, {r2,r3,r4,r5}
	subs	r0, r0, #16
	bne	clear_bss

	mov	r2, #0x63
	bl	UartPrintch

	bl	_c_main

	/* The c code should never return ! */
	b	reset


infinite_loop:
undefined_instruction:
software_interrupt:
abort_prefetch:
abort_data:
not_used:
	b	not_used

irq:
	sub lr, lr, #4
	ldr sp, =M_STACK_END_OFFSET_FROM_RAM_START
	add sp, sp, #RAM_START	/* I cannot load the value to other register */
				/* so #RAM_START is still restricted */
	stmfd sp!, {r0-r12,lr}

	ldr r1, =M_START
	ldr r2, =M_BOOT_LOADER_AREA_START_OFFSET_FROM_RAM_START
	add r1, r1, r2
	add pc, pc, r1 /* now jump to ram */
	mov r1, r1 /* pc advances 2 instructions further */
	mov r1, r1
	mov r1, r1
	bl	_c_irq
	ldmfd sp!, {r0-r12,pc}^

fiq:
	b	fiq


@If system boot from MDOC,do nessary mdoc init within the bound of 2k binary code size

@=========================================================================
@   IPL example code - ARM 32
@
@  Sequence:
@    1. Check type of Reset: (to be added by customer)
@         (Hard Reset, Soft Reset, Sleep / Resume Reset, WatchDog Reset)
@    2. In case of Soft or Sleep / Resume Reset Jump to specific RAM location,
@         in case of Hard or WatchDog Reset Continue IPL Steps
@    3. Minimal H/W Init: (to be added by customer)
@         (Set phase-locked loop (PLL) in PPCR, Setup all nesessary CSx lines)
@    4. Enable system RAM: (to be added by customer)
@         (Init Memory Controller)
@    5. Copy IPL To System RAM
@    6. Jump to IPL code in RAM
@    7. Copy SPL code from DiskOnChip Flash to system RAM
@    8. Jump to SPL code for further system initialization and loading
@
@  Note:
@    The code should NOT be used with DOC2000, DOC 2000 TSOP and MDOC
@
@  TODO#:
@    1. Define Features: SPL_MODE, etc...
@    2. Define your MDOC+ window relevant address bits
@    3. Define your System RAM loacation for storing IPL and SPL code
@    4. Set your SPL size (default is 16 Kbytes)
@    5. Set SPL signature (default is BIPO)
@    6. Insert your chipset IPL code (system initialization sequence (1) - (4))
@

@=========================================================================



@===============================================================
@ TODO #1 - Define Features
@===============================================================
MDOC_Copy:
// BOOL MDOC_Copy (ULONG size, ULONG start_address)//

//---------------------------------------------------------------
// 1. Setup destination before copying SPL and Size
//---------------------------------------------------------------
        mov     r11, #SPL_SIZE          // Get SPL Size
        ldr     r12, =SPL_RAM_ADDRESS   // Get SPL Address
//---------------------------------------------------------------
// 2. Init pointers to CDSN_IO and CDSN_CONTROL area
//       mov     r1, #CDSN_IO      // pointer to CDSN_IO (offset 0x800)
//---------------------------------------------------------------
    // set DiskOnChip window
        ldr     r1, =MDOCPBaseAddressCNTR
//----- Registers Usage: ----------------------------------------
// r0  - temp0
// r1  - temp1 - CDSN_IO (offset 0x800) and CDSN_CNTR (offset 0x1000)
// r2  - temp2
// r3  - current page pointer (page address)
// r4  - page counter
// r5  - temp3 - offset for CDSN_CNTR
// r6  - functions parameter 1
// r7  - temp4 - functions parameter 2
// r8  - page offset
// r9  - page in unit mask
// r10 - return address
// r11 - SPL Size
// r12 - pointer to SPL in RAM
//---------------------------------------------------------------
G3_start_of_ipl_copy:
//---------------------------------------------------------------
// 3. Load SPL starting address (address is in Flash)
//---------------------------------------------------------------
        mov     r3, #(SPL_START << 2)
//        IF SPL_MODE
        mov     r9, #((G3_PAGES_IN_UNIT - 1) >> 1)
//        ELSE
//        mov     r9, #(G3_PAGES_IN_UNIT - 1)
//        ENDIF
        mov     r4, #1
//---------------------------------------------------------------
// 4. Get Asic ready
//---------------------------------------------------------------
        ldrb    r2, [r1, #G3_NDOCcontrol]   // First Time Access
        mov     r2, #DOC_CTRL_NORMAL_MODE
        strb    r2, [r1, #G3_NDOCcontrol]
        mvn     r2, r2                      // move NOT
        strb    r2, [r1, #G3_NDOCcontrolConfirm]
        strh    r1, [r1, #G3_NreadAddrReg]  // write NchipId addr to addr-reg
        ldrh    r2, [r1]                    // Read chip ID.
        cmp     r2, #(MDOC512_ID << 4)
        bne     NoDocFound
	strb    r1, [r1, #G3_NdeviceSelect] // Set Floor 0
        mov     r0, #G3_CDSN_CE             // set WP | CE
        strb    r0, [r1, #G3_NflashControl]
//---------------------------------------------------------------
// 5. Look for SPL start
//---------------------------------------------------------------
G3_FindNextUnit:
    // Clean Access Error
        mov     r7, #ResetFlash_Seq         // Reset Sequence
        mov     r6, #RESET_FLASH_CMD        // Reset Command
        bl      G3_SendCommandAndSeq
        bl      G3_WaitForReady
        strb    r0, [r1, #G3_NNOPreg]       // NOP



    // Set SLC Mode
//        IF SPL_MODE
        mov     r7, #SLC_MODE_Seq           // SLC Mode Sequence
        mov     r6, #SLC_MODE_CMD           // SLC Mode Command
        bl      G3_SendCommandAndSeq
        mov     r6, #RELIABLE_SLC_MODE_CMD
        bl      G3_SendCommand
//        ENDIF // SPL_MODE

G3_continue_search:
        add     r3, r3, #G3_SPL_NEXT
    // Read Signature
        bl      G3_ReadCommandInit

    // Check For Protection Error
        add     r7, r1, #G3_NflashControl
        strh    r7, [r1, #G3_NreadAddrReg]
        ldrb    r0, [r7]
        tst     r0, #G3_ACCESS_ERR
        bne     G3_FindNextUnit // skip unit in case of protection violation

    // Set Signatue Offset
        mov     r8, #G3_SIGN_OFFSET
        bl      G3_ReadCommandContinue
        ldr     r6, =SPL_SIGN
    // Reading from CDSN IO - 4 bytes of data (signature)
        ldrh    r0, [r7, #CDSN_IO_CORR]
        ldrh    r2, [r7, #CDSN_IO_CORR]
        strb    r1, [r1, #G3_NflashDataEnd] // Finish Read Sequence
        strb    r0, [r1, #G3_NNOPreg]       // NOP
        strb    r0, [r1, #G3_NNOPreg]
        orr     r0, r0, r2, LSL #16
        cmp     r6, r0
        bne     G3_continue_search
//---------------------------------------------------------------
// 7. Issue READ command
//---------------------------------------------------------------
G3_Read_A_Area_start:
// Set Page Offset 0
        eor     r8,r8,r8
        b       G3_Read_start
G3_Read_B_Area_start:
// Set Page Offset 0x84
        mov     r8, #G3_PAGE_OFFSET
G3_Read_start:
        bl      G3_ReadCommandInit
        bl      G3_ReadCommandContinue
//---------------------------------------------------------------
// 8. Read first 512 bytes
//---------------------------------------------------------------
    // Init amount of data to read
        mov     r0, #BLOCK_DATA
        add     r0, r0, #G3_EDC_DATA
    // Read 512 bytes of data + 8 bytes Signature + 7 bytes of EDC + 1
G3_Read_first_512bytes:

        ldrh    r5, [r7, #CDSN_IO_CORR]     //   r5  <-- [r7+2]
        strh    r5, [r12], #2               // [r12] <-- r5, r12+=2
        subs    r0, r0, #2
        bne     G3_Read_first_512bytes

        strb    r1, [r1, #G3_NflashDataEnd] // Finish Read Sequence
        strb    r0, [r1, #G3_NNOPreg]
        strb    r0, [r1, #G3_NNOPreg]
    // Check if even or odd page is read
        cmp     r8, #0
    // EDC mode is applied only to even page
        bne     G3_NoEdcErrorA
        mov     r8, #1
        add     r0, r1, #G3_NECCcontrol_1
        strh    r0, [r1, #G3_NreadAddrReg]
        ldrb    r0, [r0]
        tst     r0, #G3_EDC_ERROR_MASK
        beq     G3_NoEdcErrorA
        sub     r12, r12, #BLOCK_DATA
        sub     r8, r8, #1
G3_NoEdcErrorA:
        sub     r12, r12, #G3_EDC_DATA      // Restore r12 to SPL Addr
        cmp     r8, #0
        beq     G3_Read_B_Area_start        // EDC Error
//---------------------------------------------------------------
// 9. Check if SPL is already copied
//---------------------------------------------------------------
G3_read_Next:
        cmp     r4, r11
        beq     JumpToSPL

//        IF SPL_MODE
        add     r3, r3, #2
//        ELSE
//        add     r3, r3, #1                  // page address
//        ENDIF // SPL_MODE
    // Put into r0 exact number of pages that was read in current unit
        and     r0, r9, r4                  // R0 <- R4 & #(PAGES_IN_UNIT - 1)
        add     r4, r4, #1                  // page counter
        cmp     r0, #0
        bne     G3_Read_A_Area_start        // read in current unit
        sub     r3, r3, #G3_PAGES_IN_UNIT   // will be incremented later
        b       G3_FindNextUnit             // goto next unit



//---------------------------------------------------------------
// 10. Branch to SPL located in system RAM for further initialization
//---------------------------------------------------------------
NoDocFound:
//        mov     r0, #FALSE
//        b       ReturnToCaller
        b .
JumpToSPL:

//        mov     r0, #TRUE
ReturnToCaller:


    //////    setgreen:
    //////   ldr     r0,     =xlli_GPIOREGS_PHYSICAL_BASE

//////       mov     r2, #0x2000
//////       str     r2,   [r0,#xlli_GPSR2_offset]

		ldr	r1, =RAMBEGIN
		mov	pc, r1


//===============================================================
//       Send Read Command Init
//       On Entry: Nothing
//       On exit: r6, r7, r10 destroyed
//===============================================================
G3_ReadCommandInit:
        mov     r10, lr
        mov     r7, #READ_A_Seq             // Select Area A Command
        mov     r6, #READ_A_FLASH_CMD
        bl      G3_SendCommandAndSeq
        mov     r7, #READ_Seq               // Read Command to Plane 0
        mov     r6, #READ_CMD
        bl      G3_SendCommandAndSeq

        mov     r6, #G3_PLANE_0             // Address to Plane 0
        bl      G3_SendAddress
        mov     r6, #READ_CMD               // Read Command to Plane 1
        bl      G3_SendCommand
        mov     r6, #G3_PLANE_1             // Address to Plane 1
        bl      G3_SendAddress
        mov     pc, r10
//===============================================================
//       Send Read Command Continue
//       On Entry: r8 = Page Offset
//       On exit:  r7 -> 0x800, r6, r10 destroyed
//===============================================================
G3_ReadCommandContinue:
        mov     r10, lr
        mov     r6, #MULTI_READ_CMD
        bl      G3_SendCommand
        bl      G3_WaitForReady
        mov     r6, #ADDR_INPUT_FOR_REG_READ
        bl      G3_SendCommand

        strb    r8, [r1, #G3_NflashAddress] // r8[0..7]   -->  0..7
        strb    r8, [r1, #G3_NNOPreg]

        mov     r6, #REGISTER_READ_CMD
        bl      G3_SendCommand

        bl      G3_SetEdcMode

        ldr     r7, =MDOCPBaseAddressIO     // r7 <- 0x800
        strh    r7, [r1, #G3_NreadAddrReg]
        mov     pc, r10
//===============================================================
//       Set EDC Mode for 512 + 15 data
//       On Entry: Nothing
//       On exit: r6 destroyed
//===============================================================
G3_SetEdcMode:
        ldr     r6, =G3_EDC_VAL
        strh    r6, [r1, #G3_NECCcontrol_0]
    // 5 NOPs
        strb    r6, [r1, #G3_NNOPreg]
        strb    r6, [r1, #G3_NNOPreg]
        strb    r6, [r1, #G3_NNOPreg]
        strb    r6, [r1, #G3_NNOPreg]
        strb    r6, [r1, #G3_NNOPreg]
        mov     pc, lr
//===============================================================
//       Send Command and Sequence
//       On Entry: r6 = Type of Command, r7 = Type of Sequence
//       On exit: r5 destroyed
//===============================================================
G3_SendCommandAndSeq:
        strb    r7, [r1, #G3_NflashSequence]// Send Sequence
G3_SendCommand:
        strb    r6, [r1, #G3_NflashCommand] // Send Command
        strb    r6, [r1, #G3_NNOPreg]
        strb    r6, [r1, #G3_NNOPreg]
        mov     pc, lr
//===============================================================
//       Send Address
//       On Entry: r6 = Plane: 0 or 1
//                 r3 = Address on flash in pages
//       On exit: r0 destroyed
//===============================================================
G3_SendAddress:
        orr     r0, r3, r6                  // Set Plane: 0 or 1
        strb    r0, [r1, #G3_NflashAddress] // r3[0..7]   -->  9..16
        mov     r0, r0, LSR #8
        strb    r0, [r1, #G3_NflashAddress] // r3[8..15]  -->  17..24
        mov     r0, r0, LSR #8
        strb    r0, [r1, #G3_NflashAddress] // r3[16..23] -->  25..27
    // Address Pipe Term
        strb    r0, [r1, #G3_NNOPreg]
        mov     pc, lr
//===============================================================
//       WaitForReady
//       On exit: r0, r7 destroyed
//===============================================================
G3_WaitForReady:
    // 4 NOPs
        strb    r0, [r1, #G3_NNOPreg]
        strb    r0, [r1, #G3_NNOPreg]
        strb    r0, [r1, #G3_NNOPreg]
        strb    r0, [r1, #G3_NNOPreg]
    // Wait For Ready - wait untill (value & 0x01) equals to 0x01
        add     r7, r1, #G3_NflashControl
        strh    r7, [r1, #G3_NreadAddrReg]
G3_WaitForReadyLoop:
        ldrb    r0, [r7]
        movs    r0, r0, LSL #G3_RB_SHIFT
        beq     G3_WaitForReadyLoop
        mov     pc, lr
/////////////////////////////End of MDOC_Copy///////////////////////////////////



Init_Uart:

	ldr    r0,  = BULVERDE_BASE_REG_PA_BTUART @ use BTUART for debug port
	mov    r2,  #0x08	           @ set baudrate 115200

	mov    r1,  #0x0	           @ Zero out a work register
	str    r1,  [r0, #BT_IER_OFFSET]   @ Zero out Interrupt Enable Register
	str    r1,  [r0, #BT_FCR_OFFSET]   @ Zero out FIFO Control Register
	str    r1,  [r0, #BT_LCR_OFFSET]   @ Zero out Line Control Register
	str    r1,  [r0, #BT_MCR_OFFSET]   @ Zero out Modem Control Register
	str    r1,  [r0, #BT_ISR_OFFSET]   @ Zero out IR bit register
	ldr    r1,  [r0, #BT_MSR_OFFSET]   @ Read MSR once to clear bits

	mov    r1,  #0x83	           @ Set up divisor latch bit (DLAB), 8 bit character, no parity, 1 stop bit
	str    r1,  [r0,  #BT_LCR_OFFSET]  @ Set DLAB bit

	str    r2,  [r0,  #BT_DLL_OFFSET]  @ set baud rate
	ldr    r1,  =0x0	           @ Insure high baud rate byte is zero
	str    r1,  [r0,  #BT_DLH_OFFSET]
	ldr    r1,  [r0,  #BT_LCR_OFFSET]  @ Get LCR values
	bic    r1,  r1,   #DLAB            @ Clear DLAB bit
	str    r1,  [r0,  #BT_LCR_OFFSET]  @ Write the value back out
	mov    r1,  #0x07	           @ This value will clear the TX and RX FIFOs
	str    r1,  [r0,  #BT_FCR_OFFSET]  @ ... and enabale the FIFOs for use.

	mov    r1,  #0x40	           @ set unit enable bit
	str    r1,  [r0,  #BT_IER_OFFSET]  @ enable the UART

    // Enable the BTUART clock
    mov	r0, #0x1300000
    orr	r0, r0, #0x40000004
    ldr r1, [r0]
    orr r1, r1, #0x80
    str r1, [r0]

	mov    pc, lr	                   @ Return to calling program

.global UartPrintch
UartPrintch:

bitset:
      ldr    r0,  = BULVERDE_BASE_REG_PA_BTUART
      ldr    r1,  [r0, #BT_LSR_OFFSET]	   @  Get Line Status Register Data
      ands   r1,  r1,  #TDRQ               @  Is TDRQ (Transmit Data Request) bit set?
      beq    bitset	                   @  No - loop until it is
      strb   r2,  [r0, #BT_THR_OFFSET]	   @  It's ready! - output byte to buffer
      mov    pc,  lr	                   @  Return to caller
////////////////////////////////End of UART/////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
PREINIT:

    //**************************************************************************
    // Set processor into supervisior mode (SVC) and disable IRQ & FIQ
    //
    //ldr     r0, =(Mode_SVC | NoIntsMask)
    //msr     cpsr_c, r0

    //**************************************************************************
    // Grab the CPU ID off of CP15, stuff it into Driver Globals
    //
    mrc     p15, 0, r9, c0, c0, 0   // Grab CPU ID
    and     r9, r9, #0xF            // Grab only the lowest nibble as it's all
                                    //     we care about

    //**************************************************************************
    // Disable the MMU and gang regardless of why we are here.
    //
    ldr     r0, =0x2041             // enable access to all coprocessors
    mcr     p15, 0, r0, c15, c1, 0
    CPWAIT  r0

    ldr     r0, =0x00000078         // get a zero to turn things off (must write bits[6:3] as 1's)
    mcr     p15, 0, r0, c1, c0, 0   // Turn off MMU, I&D Caches, WB
    CPWAIT  r0

    ldr     r0, =0x00000000         // get a zero to turn things off
    mcr     p15, 0, r0, c8, c7, 0   // flush (invalidate) I/D tlb's

    mcr     p15, 0, r0, c7, c7, 0   // flush (invalidate) I/D caches

    mcr     p15, 0, r0, c7, c10, 4  // Drain the write buffer

    nop
    nop
    nop

    mvn     r0, #0                  // grant manager access to all domains
    mcr     p15, 0, r0, c3, c0, 0

// Soft Resets: Info carried in R10.  If soft reset, this could be the second
//     time through (if loaded from Eboot).  In that case, r10 will be nonzero,
//     so use that to skip redundant operations that would also corrupt r10.

    //ands    r10, r10, r10
    //beq     got_SOFT_RESET_PREINIT

    //**************************************************************************
    // Read & Init Reset Cause bits in RCSR(POWER MANAGER & RESET CONTROLLER)
    //
    ldr     r0, =BULVERDE_BASE_REG_PA_PWR
    ldr     r10, [r0, #RCSR_OFFSET]

    // extract the reset cause bits
    //
    mov     r2, #RCSR_ALL           // Mask RCSR
    and     r10, r10, r2            // r10 now holds the conditioned Reset Reason

    // clear the reset cause bits (they're sticky)
    //
    str     r2, [r0, #RCSR_OFFSET]

    //**************************************************************************
    // Read and store PSSR, too - it will be reset later, after GPIOs are initialized.
    // Unclear when we'll need this information, but don't throw a good status away.
    // **BMAN:  We really should stick this into driver_globs so that we are not so limited on our register usage!!

    ldr     r0, =BULVERDE_BASE_REG_PA_PWR
    ldr     r12, [r0, #PSSR_OFFSET]

    // Set VIDAE and BIDAE for VDD/Batt Fault -->IDA
    //
    mov     r1, #(PMCR_BIDAE|PMCR_VIDAE) // configure for imprecise dAbort on VDD and BATT Faults.  *Can set up as an intrerrupt if desired*
    str     r1, [r0, #PMCR_OFFSET]

    // extract the reset cause bits
    //
    mov     r2,  #PSSR_VALID_MASK   // Mask PSSR (All in lower byte)
    and     r12,  r12,  r2          // r12 now holds the conditioned PSSR
    mov     r12,  r12,  lsl #16     // Move to upper half of register
    orr     r10,  r10,  r12         // R10 now has RCSR in lower half and PSSR in upper.

got_SOFT_RESET_PREINIT:

    mov     pc, lr
/////////////////////////////End of PREINIT/////////////////////////////////////


@*********************************************************************************************
@
@ *************************************
@ **********                 **********
@ ********** CONFIGURE GPIOs **********
@ **********                 **********
@ *************************************
@
@ This subroutine sets up the GPIO pins in accordance with the values contained in the platform include file.
@
@ NOTES: Written for the PXA27x Processor on the Mainstone Development Platform.
@
Init_GPIO:

//      Get GPIO registers base address and configure all GPIO lines.
//
        ldr     r0,  =xlli_GPIOREGS_PHYSICAL_BASE   // Load the GPIO register block base address

        ldr     r1,  =xlli_GPSR0_value              // Get the pin set values for GPSR0
        str     r1,  [r0, #xlli_GPSR0_offset]       // Write the R0 values

        ldr     r2,  =xlli_GPSR1_value              // Get the pin set values for GPSR1
        str     r2,  [r0, #xlli_GPSR1_offset]       // Write the R1 values

        ldr     r1,  =xlli_GPSR2_value              // Get the pin set values for GPSR2
        str     r1,  [r0, #xlli_GPSR2_offset]       // Write the R2 values

        ldr     r2,  =xlli_GPSR3_value              // Get the pin set values for GPSR3
        str     r2,  [r0, #xlli_GPSR3_offset]       // Write the R3 values

        ldr     r1,  =xlli_GPCR0_value              // Get the pin clear values for GPCR0
        str     r1,  [r0, #xlli_GPCR0_offset]       // Write the R0 values

        ldr     r2,  =xlli_GPCR1_value              // Get the pin clear values for GPCR1
        str     r2,  [r0, #xlli_GPCR1_offset]       // Write the R1 values

        ldr     r1,  =xlli_GPCR2_value              // Get the pin clear values for GPCR2
        str     r1,  [r0, #xlli_GPCR2_offset]       // Write the R2 values

        ldr     r2,  =xlli_GPCR3_value              // Get the pin clear values for GPCR3
        str     r2,  [r0, #xlli_GPCR3_offset]       // Write the R3 values

        ldr     r1,  =xlli_GPDR0_value              // Get the pin direction values for GPDR0
        str     r1,  [r0, #xlli_GPDR0_offset]       // Write the R0 values

        ldr     r2,  =xlli_GPDR1_value              // Get the pin direction values for GPDR1
        str     r2,  [r0, #xlli_GPDR1_offset]       // Write the R1 values

        ldr     r1,  =xlli_GPDR2_value              // Get the pin direction values for GPDR2
        str     r1,  [r0, #xlli_GPDR2_offset]       // Write the R2 values

        ldr     r2,  =xlli_GPDR3_value              // Get the pin direction values for GPDR3
        str     r2,  [r0, #xlli_GPDR3_offset]       // Write the R3 values

        ldr     r1,  =xlli_GAFR0_L_value            // Get the pin alt function values for GAFR0_L
        str     r1,  [r0, #xlli_GAFR0_L_offset]     // Write the R0_L values

        ldr     r2,  =xlli_GAFR0_U_value            // Get the pin alt function values for GAFR0_U
        str     r2,  [r0, #xlli_GAFR0_U_offset]     // Write the R0_U values

        ldr     r1,  =xlli_GAFR1_L_value            // Get the pin alt function values for GAFR1_L
        str     r1,  [r0, #xlli_GAFR1_L_offset]     // Write the R1_L values

        ldr     r2,  =xlli_GAFR1_U_value            // Get the pin alt function values for GAFR1_U
        str     r2,  [r0, #xlli_GAFR1_U_offset]     // Write the R1_U values

        ldr     r1,  =xlli_GAFR2_L_value            // Get the pin alt function values for GAFR2_L
        str     r1,  [r0, #xlli_GAFR2_L_offset]     // Write the R2_L values

        ldr     r2,  =xlli_GAFR2_U_value            // Get the pin alt function values for GAFR2_U
        str     r2,  [r0, #xlli_GAFR2_U_offset]     // Write the R2_U values

        ldr     r1,  =xlli_GAFR3_L_value            // Get the pin alt function values for GAFR3_L
        str     r1,  [r0, #xlli_GAFR3_L_offset]     // Write the R3_L values

        ldr     r2,  =xlli_GAFR3_U_value            // Get the pin alt function values for GAFR3_U
        str     r2,  [r0, #xlli_GAFR3_U_offset]     // Write the R3_U values
//
//      The RDH and PH bits on Bulverde must be set to enable updated GPIO pins.
//      These are sticky bits.
//
        ldr     r0, =xlli_PMRCREGS_PHYSICAL_BASE
        mov     r2, #(xlli_PSSR_PH | xlli_PSSR_RDH) // Set the PH and RDH bits to enable all GPIOs
        str     r2, [r0, #xlli_PSSR_offset]         // Enable all GPIO lines


        mov     pc, lr                              // Return to calling program
/////////////////////////////End of Init_GPIO///////////////////////////////////


Init_Mem:

// ***** STEP 1: *****
//
// Delay 200 uS
//

        ldr     r2, =xlli_OSTREGS_PHYSICAL_BASE // Load OS timer base address
        ldr     r3, [r2, #xlli_OSCR0_offset]    // Fetch starting value of OSCR0
        add     r3, r3,  #0x300                 // Really 0x2E1 is about 200usec, so 0x300 should be plenty
xlli_3:
	    ldr     r1, [r2, #xlli_OSCR0_offset]    // Fetch current OSCR0 value
        cmp     r1, r3                          // Is the timer past the time out value?
        bmi     xlli_3                           // No - Loop until it is
//
//  STEP 1 - 1st bullet: Write MSC0, MSC1 and MSC2 (the order is not important)
//  *******************
//
//       The value that is loaded for MSC0 depends on which FLASH memory was used to
//       boot from as determined by the switch position of SW2 (SWAP FLASH) on the
//       Mainstone board. To get the position of this switch, GPIO line #73 must be sensed.
//

//
//       It can take many cycles for the GPIO setting to take effect before the read can be
//       issued. The delay is based on clock cycles rather than elaped time so a simple
//       do-nothing loop will do the trick.
//
//////////////        mov     r1,  #0x600                         // Init counter
//////////////  xlli_4
//////////////	      subs    r1,  r1,  #1                        // Decrement counter
//////////////        bne     xlli_4                              // Loop until zero


        ldr	    r1,  =xlli_MSC0_DC_value

//       Finally - Write the memory control registers
//
        ldr     r4,  =xlli_MEMORY_CONFIG_BASE   // Get memory controller base address

        str     r1,  [r4, #xlli_MSC0_offset]    // Write the value out
        ldr     r1,  [r4, #xlli_MSC0_offset]    // Read back to latch the data

        ldr     r2,  =xlli_MSC1_value           // Get MSC1 setting
        str     r2,  [r4, #xlli_MSC1_offset]    // Write the value out
        ldr     r2,  [r4, #xlli_MSC1_offset]    // Read back to latch the data

        ldr     r1,  =xlli_MSC2_value           // Get MSC2 setting
        str     r1,  [r4, #xlli_MSC2_offset]    // Write the value out
        ldr     r1,  [r4, #xlli_MSC2_offset]    // Read back to latch the data

//
//  STEP 1 - 2nd bullet: Write MECR, MCMEM0, MCMEM1, MCATT0, MCATT1, MCIO0, MCIO1 (order not important)
//  *******************
//
        ldr     r2,  =xlli_MECR_value           // write MECR
        str     r2,  [r4, #xlli_MECR_offset]

        ldr     r1,  =xlli_MCMEM0_value         // write MCMEM0
        str     r1,  [r4, #xlli_MCMEM0_offset]

        ldr     r2,  =xlli_MCMEM1_value         // write MCMEM1
        str     r2,  [r4, #xlli_MCMEM1_offset]

        ldr     r1,  =xlli_MCATT0_value         // write MCATT0
        str     r1,  [r4, #xlli_MCATT0_offset]

        ldr     r2,  =xlli_MCATT1_value         // write MCATT1
        str     r2,  [r4, #xlli_MCATT1_offset]

        ldr     r1,  =xlli_MCIO0_value          // write MCIO0
        str     r1,  [r4, #xlli_MCIO0_offset]

        ldr     r2,  =xlli_MCIO1_value          // write MCIO1
        str     r2,  [r4, #xlli_MCIO1_offset]
//
//  STEP 1 - 3rd bullet: Write FLYCNFG
//  *******************
//
        ldr     r1,  =xlli_FLYCNFG_value        // write FLYCNFG
        str     r1,  [r4, #xlli_FLYCNFG_offset]
//

//
//  STEP 1 - 4th bullet: SKIPPED (used only when coming out of sleep)
//  *******************
//
//     (If required, this would be a write to MDCNFG with enable bits deasserted.)

//
//  STEP 1 - 5th bullet: update MDREFR settings
//  *******************
//
        ldr     r2,  [r4, #xlli_MDREFR_offset] // Get reset state of MDREFR
        mov     r2,  r2, lsr #0xC              // Shift data 12 bits (0xC) to the right
        mov     r2,  r2, lsl #0xC              // and shift left 12 bits (Clears DRI field)
                                               // because left shifts fill bits with zeros.

        ldr     r1,  =xlli_MDREFR_value        // Fetch MDREFR value for this platform
        mov     r1,  r1, lsl #0x14             // use shifts to extract the DRI field using
        mov     r1,  r1, lsr #0x14             // same method as before but shifting 20 (0x14)
                                               // bits left, then right again.

        orr     r2,  r2, r1                    // insert the DRI field extracted above
        str     r2,  [r4, #xlli_MDREFR_offset] // write value with valid DRI to MDREFR

        orr     r2,  r2, #xlli_MDREFR_K0RUN    // Enable K0RUN

        bic     r2,  r2, #xlli_MDREFR_K0DB2    // Configure K0DB2

        bic     r2,  r2, #xlli_MDREFR_K0DB4    // Set K0DB4 = MemClk/4

        bic     r2,  r2, #(xlli_MDREFR_K1FREE | xlli_MDREFR_K2FREE)  // Clear free run clock bits

        orr     r2,  r2, #xlli_MDREFR_K0FREE   // Set K0FREE (as per Mainstone spec...)

        str     r2,  [r4, #xlli_MDREFR_offset] // Write back MDREFR
        //
        // Preserve MDREFR in r2
        //

// ***** STEP 2 *****
//
// For systems with Synchronous Flash
//
        ldr     r1,  =xlli_SXCNFG_value
        str     r1,  [r4, #xlli_SXCNFG_offset]


//
// ***** STEP 3 *****
//
// Clear the free run clock bits to enable the use of SDCLK for memory timing
//
        bic     r2, r2, #(xlli_MDREFR_K2FREE | xlli_MDREFR_K1FREE | xlli_MDREFR_K0FREE)

//
// set K1RUN if bank 0 installed
//

        orr     r2, r2, #xlli_MDREFR_K1RUN      // Enable SDCLK[1]
        bic     r2, r2, #xlli_MDREFR_K2DB2      // Clear K2DB2
        str     r2, [r4, #xlli_MDREFR_offset]   // write updated MDREFR
        ldr     r2, [r4, #xlli_MDREFR_offset]   // read back

        bic     r2, r2, #xlli_MDREFR_SLFRSH     // Disable self refresh
        str     r2, [r4, #xlli_MDREFR_offset]   // write updated MDREFR
        ldr     r2, [r4, #xlli_MDREFR_offset]   // read back

        orr     r2, r2, #xlli_MDREFR_E1PIN      // Assert E1PIN to enable SDCKE[1]
        str     r2, [r4, #xlli_MDREFR_offset]   // write updated MDREFR (finished with value in r2)
        ldr     r2, [r4, #xlli_MDREFR_offset]   // read back
        nop                                     // Do not remove!
        nop                                     // Do not remove!
//
// ***** STEP 4 *****
//
// Appropriately configure, but don't enable, each SDRAM partition pair
//

        ldr     r1, =xlli_MDCNFG_value          // Fetch platform value for MDCNFG

        bic     r1, r1,  #(xlli_MDCNFG_DE0 | xlli_MDCNFG_DE1)   // Disable all
        bic     r1, r1,  #(xlli_MDCNFG_DE2 | xlli_MDCNFG_DE3)   // SDRAM banks
//
//       Check for conditional def for 32 vs 16 bit bus width
//
      // IF :DEF: xlli_SDRAM_16BIT               // Set bus width to 16 bits?
      //  orr     r1, r1,  #xlli_MDCNFG_DWID0     // Set banks 0/1 for 16 bit width
      // else
      // bic     r1, r1,  #xlli_MDCNFG_DWID0     // Set banks 0/1 for 32 bit width
      //endif

        str     r1, [r4, #xlli_MDCNFG_offset]   // Write w/o enabling SDRAM banks

//
// ***** STEP 5 *****  (Delay at least 200 uS)
//
        ldr     r2,  =xlli_OSTREGS_PHYSICAL_BASE // Load OS timer base address
        ldr     r3,  [r2, #xlli_OSCR0_offset]    // Fetch starting value of OSCR0
        add     r3,  r3,  #0x300                 // Really 0x2E1 is about 200usec, so 0x300 should be plenty
xlli_5:
	ldr     r1,  [r2, #xlli_OSCR0_offset]    // Fetch current OSCR0 value
        cmp     r1,  r3                          // Is the timer past the time out value?
        bmi     xlli_5                           // No - Loop until it is
//
// ***** STEP 6 ***** (Make sure DCACHE is disabled)
//
        mrc     p15, 0, r2, c1, c0, 0           // load r2 contents of register 1 in CP 15
        bic     r2,  r2,  #xlli_CONTROL_DCACHE  // Disable D-Cache
        mcr     p15, 0, r2, c1, c0, 0           // Write back to CP15
//
// ***** STEP 7 *****
//
// Access memory *not yet enabled* for CBR refresh cycles (8)
// - CBR is generated for all banks
//
        ldr     r1, =xlli_SDRAM_PHYSICAL_BASE
        str     r1, [r1]
        str     r1, [r1]
        str     r1, [r1]
        str     r1, [r1]
        str     r1, [r1]
        str     r1, [r1]
        str     r1, [r1]
        str     r1, [r1]

        str     r1, [r1]  //  Fix for erratum #116. Makes up for ineffective 1st mem access.
                          //  This is being left in for Bulverde for the moment
//
// ***** STEP 8 *****
//
//  Re-enable D-cache if desired (we don't)

//
// ***** STEP 9 *****
//
// Re-enable SDRAM partitions
//
        ldr     r2,  [r4, #xlli_MDCNFG_offset]   // Fetch the current MDCNFG value
        orr     r2,  r2,  #xlli_MDCNFG_DE0       // Enable SDRAM bank 0
        str     r2,  [r4, #xlli_MDCNFG_offset]   // Write back MDCNFG, enabling the SDRAM bank(s)
//
// ***** STEP 10 *****
//
// Write the MDMRS register to trigger an MRS command to all enabled banks of SDRAM.
//
//



        ldr     r1,  =xlli_MDMRS_value           // Fetch platform MDMRS value
        str     r1,  [r4, #xlli_MDMRS_offset]    // Write the MDMRS value back
//
// ***** STEP 11 *****
//
// In systems with SDRAM or Synchronous Flash, optionally enable auto-power-down by setting MDREFR:APD
//

        ldr     r3,  [r4, #xlli_MDREFR_offset]   // Get MDREFR value
        orr     r3,  r3,  #xlli_MDREFR_APD       // enable auto power down
        str     r3,  [r4, #xlli_MDREFR_offset]   // Write value back

        mov     pc,  lr                         // return to calling routine
//////////////////////////////End of Init_Mem///////////////////////////////////

/* Nam9, 2004. 9. 17 */

	.align 4
bss_start:	.word	___bss_start
bss_end	:	.word	___bss_end
	.align 4
	.set M_START, RAM_START
	.set M_BOOT_LOADER_AREA_START_OFFSET_FROM_RAM_START, RAM_BOOT_LOADER_AREA_START_OFFSET_FROM_RAM_START
	.set M_BOOT_LOADER_AREA_LENGTH, RAM_BOOT_LOADER_AREA_LENGTH
	.set M_STACK_END_OFFSET_FROM_RAM_START, RAM_STACK_END_OFFSET_FROM_RAM_START
